package org.example.order.service.impl;

import cn.hutool.core.lang.UUID;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.example.core.constant.TokenConstants;
import org.example.core.exception.CustomException;
import org.example.core.exception.ExceptionCode;
import org.example.core.exception.order.CreateOrderException;
import org.example.core.to.mq.OrderTo;
import org.example.core.utils.PageUtils;
import org.example.core.utils.R;
import org.example.order.api.*;
import org.example.order.api.domain.LockedStock;
import org.example.order.api.domain.StockItem;
import org.example.order.api.module.*;
import org.example.order.bo.ConfirmOrderBo;
import org.example.order.constant.OrderRedisConstants;
import org.example.order.dao.OrderDao;
import org.example.order.dao.OrderItemDao;
import org.example.order.dto.OrderDto;
import org.example.order.dto.OrderItemDto;
import org.example.order.entity.OrderEntity;
import org.example.order.entity.OrderItemEntity;
import org.example.order.orderEnum.PayEnumType;
import org.example.order.vo.*;
import org.example.rabbitmq.service.RabbitService;
import org.example.redis.service.RedisService;
import org.example.security.handler.SecurityHandler;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.example.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service("orderService")
public class OrderServiceImpl implements OrderService {

    @Autowired
    private OrderDao orderDao;
    @Autowired
    private OrderItemDao orderItemDao;
    @Autowired
    private MemberService memberService;
    @Autowired
    private CartService cartService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private ProductService productService;
    @Autowired
    private WareHouseService wareHouseService;
    @Autowired
    private CouponService couponService;
    @Autowired
    private RabbitService rabbitService;

    // 开始时间戳
    private static final long BEGIN_TIMESTAMP = 1704585600L;
    // 序列号位数
    private static final int COUNT_BITS = 32;

    private static final DefaultRedisScript<Long> ORDER_SCRIPT;

    static {
        ORDER_SCRIPT = new DefaultRedisScript<Long>();
        ORDER_SCRIPT.setLocation(new ClassPathResource("order.lua"));
        ORDER_SCRIPT.setResultType(Long.class);
    }

    // TODO 考虑异步优化
    @Override
    public OrderConfirmVo confirmOrder(ConfirmOrderBo confirmOrderBo) {
        OrderConfirmVo confirmVo = new OrderConfirmVo();
        String memberId = SecurityHandler.getData().get(TokenConstants.MEMBER_ID);

        List<OrderItem> buildItems = null;
        if (confirmOrderBo.getType() == PayEnumType.CART_ORDER.getCode()){
            // 购物车
            buildItems = buildOrderItems(memberId);
        }
        if (confirmOrderBo.getType() == PayEnumType.NOW_ORDER.getCode()){
            // 立即购买
            if (confirmOrderBo.getCount() == null || confirmOrderBo.getCount() <= 0){
                throw new CustomException(ExceptionCode.VALIDATE_ERROR.getCode(), ExceptionCode.VALIDATE_ERROR.getMsg());
            }
            buildItems = buildOrderItems(confirmOrderBo.getSkuId(), confirmOrderBo.getCount());

        }

        BigDecimal totalPrice = countTotalPrice(buildItems);    // 计算总价
        BigDecimal payPrice = countPayPrice(buildItems);    // 计算应付价格

        List<MemberAddress> address = memberService.address(memberId).getData();     // 获取会员地址
        confirmVo.setAddress(address);  // 设置会员地址
        confirmVo.setOrderItem(buildItems); // 设置订单列表
        confirmVo.setTotalPrice(totalPrice);  // 设置总价
        confirmVo.setPayPrice(payPrice);  // 应付总价

        String token = UUID.randomUUID().toString(true);
        redisService.setObject(OrderRedisConstants.ORDER_TOKEN + memberId, token, 30L, TimeUnit.MINUTES);
        confirmVo.setToken(token);
        return confirmVo;
    }

    // 购物车创建订单
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<?> createOrder(OrderRestVo orderRestVo) {
        String memberId = SecurityHandler.getData().get(TokenConstants.MEMBER_ID);
        String memberName = SecurityHandler.getData().get(TokenConstants.MEMBER_NAME);
        // 验证令牌
        Long result = (Long) redisService.execute(ORDER_SCRIPT, Collections.singletonList(OrderRedisConstants.ORDER_TOKEN + memberId), orderRestVo.getToken());
        if (result == 0L) {
            // 失败
            return R.error();
        }

        List<OrderItem> buildOrderItems = null;
        if (orderRestVo.getType() == PayEnumType.CART_ORDER.getCode()){
            buildOrderItems = buildOrderItems(memberId);
        }
        if (orderRestVo.getType() == PayEnumType.NOW_ORDER.getCode()){
            buildOrderItems = buildOrderItems(orderRestVo.getSkuId(), orderRestVo.getCount());
        }
        if (buildOrderItems == null){
            return R.error();
        }
        String orderSn = createOrderSn(orderRestVo.getPayType(), orderRestVo.getSourceType());  // 订单号
        Set<Long> spuIds = buildOrderItems.stream().map(OrderItem::getSpuId).collect(Collectors.toSet());   // 收集spuIds
        Map<Long, SpuInfo> spuData = productService.spuList(spuIds).getData();  // 查询spu信息

        List<OrderItemEntity> orderItem = new ArrayList<>(buildOrderItems.size());  // 构建每一个订单项
        for (OrderItem item : buildOrderItems) {
            // 构建订单项
            OrderItemEntity itemEntity = new OrderItemEntity();
            itemEntity.setOrderSn(orderSn);
            // spu信息
            SpuInfo spuInfo = spuData.get(item.getSpuId());
            itemEntity.setSpuId(spuInfo.getSpuId());
            itemEntity.setSpuBrand(spuInfo.getBrandId());
            itemEntity.setSpuName(spuInfo.getSpuTitle());
            itemEntity.setCategoryId(spuInfo.getCategoryId());
            // sku信息
            itemEntity.setSkuId(item.getSkuId());
            itemEntity.setSkuName(item.getSkuTitle());
            itemEntity.setSkuPrice(item.getPrice());
            itemEntity.setPayPrice(item.getPayPrice());
            itemEntity.setSkuPic(item.getSkuDefaultImg());
            itemEntity.setSkuQuantity(item.getCount());
            itemEntity.setSkuAttrsValues(item.getAttribute());
            orderItem.add(itemEntity);
        }

        // 构建订单
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setNote(orderRestVo.getNote()); // 订单备注
        orderEntity.setMemberId(Long.parseLong(memberId));  // 会员id
        orderEntity.setOrderSn(orderSn);    // 订单号
        orderEntity.setMemberUsername(memberName);  // 会员名

        // 收货地址信息
        MemberAddress memberAddress = memberService.addressInfo(orderRestVo.getAddressId(), memberId).getData();
        orderEntity.setReceiverName(memberAddress.getName());
        orderEntity.setReceiverPhone(memberAddress.getPhone());
        orderEntity.setReceiverProvince(memberAddress.getProvince());
        orderEntity.setReceiverCity(memberAddress.getCity());
        orderEntity.setReceiverRegion(memberAddress.getRegion());
        orderEntity.setReceiverDetailAddress(memberAddress.getDetailAddress());

        orderEntity.setConfirmStatus(0);
        BigDecimal totalPrice = countTotalPrice(buildOrderItems).setScale(2, RoundingMode.HALF_UP);
        orderEntity.setTotalAmount(totalPrice); // 总金额
        BigDecimal payPrice = countPayPrice(buildOrderItems).setScale(2, RoundingMode.HALF_UP);
        orderEntity.setPayAmount(payPrice);    // 应付金额
        orderEntity.setPromotionAmount(totalPrice.subtract(payPrice).setScale(2, RoundingMode.HALF_UP));
        orderEntity.setPayType(orderRestVo.getPayType());   // 付款方式
        orderEntity.setSourceType(orderRestVo.getSourceType());     // 来源
        orderEntity.setCreateTime(LocalDateTime.now());
        orderEntity.setOutTime(LocalDateTime.now().plusMinutes(15L));

        orderDao.saveOrder(orderEntity);    // 保存订单
        orderItemDao.saveOrderItem(orderItem, orderEntity.getId());   // 保存订单项

        // 锁定库存
        LockedStock lockedStock = new LockedStock();
        lockedStock.setOrderSn(orderSn);
        lockedStock.setOrderId(orderEntity.getId());
        ArrayList<Long> skuIds = new ArrayList(buildOrderItems.size());
        List<StockItem> stockItem = buildOrderItems.stream().map(item -> {
            StockItem stock = new StockItem();
            stock.setSkuId(item.getSkuId());
            stock.setCount(item.getCount());
            skuIds.add(stock.getSkuId());
            return stock;
        }).collect(Collectors.toList());
        lockedStock.setStockItem(stockItem);
        // 锁定库存
        R<?> stock = wareHouseService.lockedStock(lockedStock);
        if (stock.getCode() == 0) {
            OrderTo orderTo = new OrderTo(orderEntity.getId(), orderEntity.getOrderSn());
            rabbitService.sendMessage("order-event-exchange", "order.create.order", orderTo);   // 发送消息
            // 删除购物车数据
            if (orderRestVo.getType() == PayEnumType.CART_ORDER.getCode()){
                R<?> deletes = cartService.deletes(skuIds, memberId);
                if (deletes.getCode() == 0){
                    return R.ok(orderEntity.getId());
                }
                throw new CreateOrderException("下单失败");
            }
            return R.ok(orderEntity.getId());
        }else {
            throw new CreateOrderException("商品库存不足");
        }
    }


    // 查询订单状态
    @Override
    public Integer queryOrderStatus(String orderSn) {
        return orderDao.getOrderStatusBySn(orderSn);
    }

    // 关闭订单
    @Override
    public void closeOrder(OrderTo order) {
        // 当前订单最新状态
        Integer status = orderDao.getOrderStatusById(order.getId());
        // 关单
        if (status != null && status == 0){
            orderDao.updateOrderStatus(order.getId(), 5);
            rabbitService.sendMessage("order-event-exchange", "order.release.other.#", order);
        }
    }

    /**
     * 查询订单和订单项的详细信息
     * @param id
     * @return
     */
    @Override
    public OrderRespVo queryOrderInfo(Long id) {
        long memberId = Long.parseLong(SecurityHandler.getData().get(TokenConstants.MEMBER_ID));
        // 查询订单详细信息
        OrderRespVo orderRespVo = orderDao.getOrderInfoById(id, memberId);
        // 查询订单项信息
        List<OrderItemEntity> orderItemEntities = orderItemDao.getOrderItemInfoByOrderId(id);
        orderRespVo.setOrderItemEntities(orderItemEntities);
        return orderRespVo;
    }

    // 用户查询订单
    @Override
    public PageUtils queryMemberOrder(Integer pageNum, Integer pageSize, Integer status) {
        PageHelper.startPage(pageNum, pageSize);
        String memberId = SecurityHandler.getData().get(TokenConstants.MEMBER_ID);
        List<OrderMemberInfoVo> orderMemberInfoVo;
        if (status == null || status == -1){
            orderMemberInfoVo = orderDao.getOrderInfoByMemberIdAll(Long.parseLong(memberId));
        }else {
            orderMemberInfoVo = orderDao.getOrderInfoByMemberId(Long.parseLong(memberId), status);
        }
        for (OrderMemberInfoVo infoVo : orderMemberInfoVo) {
            List<OrderItemEntity> orderItemInfoByOrderId = orderItemDao.getOrderItemInfoByOrderId(infoVo.getId());
            infoVo.setOrderItems(orderItemInfoByOrderId);
        }
        return new PageUtils(new PageInfo<>(orderMemberInfoVo));
    }

    // 逻辑删除订单
    @Override
    public int deleteOrder(Long orderId) {
        long memberId = Long.parseLong(SecurityHandler.getData().get(TokenConstants.MEMBER_ID));
        return orderDao.deleteOrder(orderId, memberId);
    }

    // 确认收货
    @Override
    public int updateConfirm(Long orderId) {
        long memberId = Long.parseLong(SecurityHandler.getData().get(TokenConstants.MEMBER_ID));
        return orderDao.updateConfirm(orderId, memberId);
    }

    // 取消订单
    @Override
    public int cancelOrder(Long orderId) {
        long memberId = Long.parseLong(SecurityHandler.getData().get(TokenConstants.MEMBER_ID));
        return orderDao.cancelOrder(orderId, memberId);
    }

    // 后台查询订单
    @Override
    public PageUtils list(OrderDto orderDto) {
        if (orderDto.needLimit()){
            PageHelper.startPage(orderDto.getPage(), orderDto.getPageSize());
        }
        List<OrderVo> vos = orderDao.list(orderDto);
        return new PageUtils(new PageInfo<>(vos));
    }

    @Override
    public PageUtils orderItem(OrderItemDto dto) {
        if (dto.needLimit()){
            PageHelper.startPage(dto.getPage(), dto.getPageSize());
        }

        List<OrderItemEntity> orderItemInfoByOrderId = orderItemDao.getOrderItemInfoByOrderId(dto.getOrderId());
        return new PageUtils(new PageInfo<>(orderItemInfoByOrderId));
    }

    // 购物车构建订单项
    private List<OrderItem> buildOrderItems(String memberId) {
        List<OrderItem> orderItems = cartService.selected(memberId).getData();// 选中的购物项
        List<Long> skuIds = orderItems.stream().map(OrderItem::getSkuId).collect(Collectors.toList());

        Map<Long, SkuInfo> skuInfos = productService.queryCartSkus(skuIds).getData();
        Map<Long, Preferential> preferential = couponService.getPreferential(skuIds).getData();

        List<OrderItem> collect = orderItems.stream().peek(item -> {
            BeanUtils.copyProperties(skuInfos.get(item.getSkuId()), item);
        }).collect(Collectors.toList());

        List<OrderItem> buildItems = buildPayPrice(collect, preferential); // 构建优惠后每一项的到手价
        return buildItems;
    }

    // 立即购买构建订单项
    private List<OrderItem> buildOrderItems(Long skuId, Integer count) {

        Map<Long, SkuInfo> skuInfos = productService.queryCartSkus(Collections.singletonList(skuId)).getData();
        Map<Long, Preferential> preferential = couponService.getPreferential(Collections.singletonList(skuId)).getData();

        ArrayList<OrderItem> collect = new ArrayList<>();
        OrderItem orderItem = new OrderItem();
        BeanUtils.copyProperties(skuInfos.get(skuId), orderItem);
        orderItem.setCount(count);
        collect.add(orderItem);
        List<OrderItem> buildItems = buildPayPrice(collect, preferential); // 构建优惠后每一项的到手价
        return buildItems;
    }

    // 计算应付的价格
    public BigDecimal countPayPrice(List<OrderItem> orderItems){
        BigDecimal payPrice = new BigDecimal("0");
        for (OrderItem item : orderItems){
            // 选中,计算优惠
            BigDecimal singleTotal = item.getPayPrice().multiply(new BigDecimal(item.getCount()));
            payPrice = payPrice.add(singleTotal);
        }
        return payPrice;
    }

    // 计算没优惠的总价
    public BigDecimal countTotalPrice(List<OrderItem> orderItems){
        BigDecimal totalPrice = new BigDecimal("0");
        for (OrderItem item : orderItems){
            // 选中,计算优惠
            BigDecimal singleTotal = item.getPrice().multiply(new BigDecimal(item.getCount()));
            totalPrice = totalPrice.add(singleTotal);
        }
        return totalPrice;
    }

    // 构建每个优惠后应付价格
    private List<OrderItem> buildPayPrice(List<OrderItem> orderItems, Map<Long, Preferential> preferential) {
        BigDecimal compareDigit = new BigDecimal("0");
        List<OrderItem> itemList = orderItems.stream().peek(item -> {
            // 数量
            BigDecimal skuCount = new BigDecimal(item.getCount());
            // 总价
            BigDecimal singleTotal = item.getPrice().multiply(skuCount);
            // 折扣
            BigDecimal ladderPrice = countLadderPrice(preferential.get(item.getSkuId()).getLadders(), item, singleTotal);
            // 满减
            BigDecimal fullPrice = countFullPrice(preferential.get(item.getSkuId()).getFullReductions(), singleTotal);
            // 找出最优价格
            if (ladderPrice.compareTo(compareDigit) > 0 && fullPrice.compareTo(compareDigit) > 0) {
                if (ladderPrice.compareTo(fullPrice) >= 0) {
                    item.setPayPrice(fullPrice.divide(skuCount, 2, RoundingMode.HALF_UP));
                } else {
                    item.setPayPrice(ladderPrice.divide(skuCount, 2, RoundingMode.HALF_UP));
                }
            } else if (ladderPrice.compareTo(compareDigit) > 0 && fullPrice.compareTo(compareDigit) <= 0) {
                item.setPayPrice(ladderPrice.divide(skuCount, 2, RoundingMode.HALF_UP));
            } else if (ladderPrice.compareTo(compareDigit) <= 0 && fullPrice.compareTo(compareDigit) > 0) {
                item.setPayPrice(fullPrice.divide(skuCount, 2, RoundingMode.HALF_UP));
            } else {
                item.setPayPrice(item.getPrice());
            }
        }).collect(Collectors.toList());

        return itemList;
    }

    // 计算满减
    private BigDecimal countFullPrice(List<FullReduction> fullReductions, BigDecimal singleTotal) {
        BigDecimal fullPrice = new BigDecimal("0");
        if (fullReductions != null && !fullReductions.isEmpty()){
            for (int j = 0; j< fullReductions.size(); j++){
                // 满足（查询时已经按full_price排序，这个满足直接结束）
                if (singleTotal.compareTo(fullReductions.get(j).getFullPrice())>=0){
                    fullPrice = singleTotal.subtract(fullReductions.get(j).getReducePrice());
                    return fullPrice;
                }
            }
        }
        return fullPrice;
    }

    // 计算则扣信息
    private BigDecimal countLadderPrice(List<Ladder> ladders, OrderItem orderItem, BigDecimal singleTotal) {
        BigDecimal ladderPrice = new BigDecimal("0");
        if (ladders != null && !ladders.isEmpty()){
            for (int i = 0; i< ladders.size(); i++){
                // 满足（查询时已经按count排序，这个满足直接结束）
                if (orderItem.getCount() >= ladders.get(i).getCount()){
                    // 则扣后的价格
                    ladderPrice = singleTotal.multiply(ladders.get(i).getDiscount());
                    return ladderPrice;
                }
            }
        }
        return ladderPrice;
    }

    // 生成订单号
    public String createOrderSn(int payType, int sourceType){
        LocalDateTime now = LocalDateTime.now();
        long second = now.toEpochSecond(ZoneOffset.UTC);
        long timestamp = second - BEGIN_TIMESTAMP;

        // 2.生成序列号
        // 获取到当天的日期,避免超过32位上线
        String format = now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        Long count = redisService.createSn(OrderRedisConstants.ORDER_SN + format);
        Long orderSn = timestamp << COUNT_BITS | count;

        // 3.拼接并返回
        return String.format("%d%d%d", orderSn, payType, sourceType);
    }
}